package com.bwton.msx.ccb.widget.camera;

import java.io.IOException;

import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;

public class SenseCameraPreview extends ViewGroup {

    private Context mContext;

    private SurfaceView mSurfaceView;

    private boolean mStartRequested;

    private boolean mSurfaceAvailable;

    private SenseCamera mCamera;

    private StartListener mStartListener;

    /**
     * SenseCameraPreview.
     *
     * @param context context.
     * @param attrs   attrs.
     */
    public SenseCameraPreview(final Context context, final AttributeSet attrs) {
        super(context, attrs);

        this.mContext = context;
        this.mStartRequested = false;
        this.mSurfaceAvailable = false;
        this.mSurfaceView = new SurfaceView(context);
        this.mSurfaceView.getHolder().addCallback(new SurfaceCallback());
        addView(this.mSurfaceView);
    }

    public void setStartListener(final StartListener listener) {
        this.mStartListener = listener;
    }

    /**
     * start with SenseCamera.
     *
     * @param senseCamera senseCamera.
     */
    public void start(final SenseCamera senseCamera) throws IOException, RuntimeException {
        if (senseCamera == null) {
            this.stop();
        }

        this.mCamera = senseCamera;

        if (this.mCamera != null) {
            this.mStartRequested = true;
            this.startIfReady();
        }
    }

    /**
     * stop.
     */
    public void stop() {
        if (this.mCamera != null) {
            this.mCamera.stop();
        }
    }

    /**
     * release.
     */
    public void release() {
        if (this.mCamera != null) {
            this.mCamera.release();
            this.mCamera = null;
        }
    }

    private void startIfReady() throws IOException, RuntimeException {
        if (this.mStartRequested && this.mSurfaceAvailable) {
            this.mCamera.start(this.mSurfaceView.getHolder());
            this.requestLayout();
            this.mStartRequested = false;
        }
    }

    // 根据摄像头分辨率按比例扩大图片的size
    @Override
    protected void onLayout(final boolean changed, final int left, final int top, final int right,
                            final int bottom) {
        if (this.mCamera != null) {
            SenseCamera.Size size = this.mCamera.getPreviewSize();
            if (size != null) {
                int cameraWidth = size.getWidth();
                int cameraHeight = size.getHeight();

                if (this.isPortraitMode()) {
                    int tmp = cameraWidth;
                    //noinspection SuspiciousNameCombination
                    cameraWidth = cameraHeight;
                    cameraHeight = tmp;
                }
                final int layoutWidth = right - left;
                final int layoutHeight = bottom - top;
                int childWidth;
                int childHeight;
                final float layoutAspectRatio = layoutWidth / (float) layoutHeight;
                final float cameraPreviewAspectRatio = cameraWidth / (float) cameraHeight;
                if (Float.compare(layoutAspectRatio, cameraPreviewAspectRatio) <= 0) {
                    childWidth = (int) (layoutHeight * cameraPreviewAspectRatio);
                    childHeight = layoutHeight;
                } else {
                    childWidth = layoutWidth;
                    childHeight = (int) (layoutWidth / cameraPreviewAspectRatio);
                }

                int widthDiff = (layoutWidth - childWidth) / 2;
                int heightDiff = (layoutHeight - childHeight) / 2;

                for (int i = 0; i < this.getChildCount(); ++i) {
                    this.getChildAt(i).layout(
                            widthDiff,
                            heightDiff,
                            childWidth + widthDiff,
                            childHeight + heightDiff);
                }

                try {
                    this.startIfReady();
                } catch (SecurityException se) {
                    se.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * convert viewRect.
     *
     * @param viewRect viewRect.
     * @return converted Rect.
     */
    public Rect convertViewRectToCameraPreview(final Rect viewRect) {
        final int cameraRotationDegrees = mCamera.getRotationDegrees();
        SenseCamera.Size size = this.mCamera.getPreviewSize();
        int cameraWidth = size.getWidth();
        int cameraHeight = size.getHeight();
        if (this.isPortraitMode()) {
            int tmp = cameraWidth;
            cameraWidth = cameraHeight;
            cameraHeight = tmp;
        }
        final int layoutWidth = this.getWidth();
        final int layoutHeight = this.getHeight();
        int childWidth;
        int childHeight;
        final float layoutAspectRatio = layoutWidth / (float) layoutHeight;
        final float cameraPreviewAspectRatio = cameraWidth / (float) cameraHeight;
        if (Float.compare(layoutAspectRatio, cameraPreviewAspectRatio) <= 0) {
            childWidth = (int) (layoutHeight * cameraPreviewAspectRatio);
            childHeight = layoutHeight;
        } else {
            childWidth = layoutWidth;
            childHeight = (int) (layoutWidth / cameraPreviewAspectRatio);
        }
        int widthDiff = (layoutWidth - childWidth) / 2;
        int heightDiff = (layoutHeight - childHeight) / 2;
        float widthRatio = (float) cameraWidth / childWidth;
        float heightRatio = (float) cameraHeight / childHeight;
        float left = (viewRect.left + Math.abs(widthDiff)) * widthRatio;
        float top = (viewRect.top + Math.abs(heightDiff)) * heightRatio;
        return new Rect((int) left,
                (int) top,
                (int) (left + viewRect.width() * widthRatio),
                (int) (top + viewRect.height() * heightRatio));
    }

    private boolean isPortraitMode() {
        final int orientation = this.mContext.getResources().getConfiguration().orientation;
        return orientation != Configuration.ORIENTATION_LANDSCAPE
                && orientation == Configuration.ORIENTATION_PORTRAIT;
    }

    public static interface StartListener {
        void onFail();
    }

    private class SurfaceCallback implements SurfaceHolder.Callback {
        @Override
        public void surfaceCreated(final SurfaceHolder surface) {
            SenseCameraPreview.this.mSurfaceAvailable = true;
            try {
                SenseCameraPreview.this.startIfReady();
            } catch (Exception e) {
                e.printStackTrace();
                if (SenseCameraPreview.this.mStartListener != null) {
                    SenseCameraPreview.this.mStartListener.onFail();
                }
            }
        }

        @Override
        public void surfaceDestroyed(final SurfaceHolder surface) {
            SenseCameraPreview.this.mSurfaceAvailable = false;
        }

        @Override
        public void surfaceChanged(final SurfaceHolder holder, final int format, final int width,
                                   final int height) {
            // noting.
        }
    }
}
